<?php
/////////////////////////////////////////////////////////////////////////////
// 
//
// workflow_system 
//
// workflow_copyright
// 
/////////////////////////////////////////////////////////////////////////////

/**
 * FILE_NAME : xmlread.class.php   FILE_PATH : \classes\libraries\xmlread.class.php
 * XML文件数据读取类(SAX 解析)
 * 最好有 iconv() 函数支持
 * 用于读取xml文件数据到一数组里,目前还不能对一些特殊的标记进行处理
 * 可为同级兄弟结点指定索引(数组下标)
 *
 * @copyright workflow_system 
 * @author workflow Develop Team 
 * @package 
 * @subpackage 
 * @version Wed Aug 08 14:57:17 CST 2007
 */


	/*
	+------------------------------------------------------------------------------------------------------
	|   功能说明： 根据类表生成树型图.
	|   调用部分 ：
	|   ========================================
	|   $node[1] = array(
	|	'node_name'=>'data',
	|	'target_type'=>0,
	|	'target_name'=>'name'
	|	);
	|	$node[2] = array(
	|	'node_name'=>'data',
	|	'target_type'=>1,
	|	'target_name'=>'value'
	|	);
	|	$hdc = new xmlRead('UTF-8',$node); //设置编码
	|	$hdc->var_use_iconv = 1;   //是否使用 iconv
	|	$hdc->xmlRead_node_config = "root";
	|	foreach($langarray as $v){
	|		$hdc->xmlRead_parser_file("example.xml");
	|		$value = $hdc->xmlRead_get_ret(); //得到数组
	|		$value = $value['root']['data'];
	|	}
	|
	+------------------------------------------------------------------------------------------------------
	*/
class xmlRead
{
	//解析器
	var $var_parser;

	//xml文件编码语言
	var $var_lang = 'UTF-8';

	//*****************************************************
	// $var_node[深度][节点名] node_name
	// $var_node[深度][目标类型] target_type
	// $var_node[深度][目标名称] target_name
	// 目标: 属性/子节点; 0/1
	// 深度: 数字 - by Mayer
	//*****************************************************
	var $var_node = array();
	var $var_index = array();

	var $var_stack = array(); //标记栈
	var $var_stack_attrs = array(); //参数栈

	//节点深度
	var $var_depth = 0;

	// $var_data[深度]; $var_data[0] 用来存 xml文件所有记录
	var $var_data = array(); //数据

	function xmlRead($lang,$node='')
	{
		if(is_array($node))
		{
			$this->var_node = $node;
		}
		
		$this->var_lang = $lang;


		

		//$this->xmlRead_parser_file($file);

	}

	/******************************************************
	* 获取xml数据记录  2005-1-17
	******************************************************/
	function xmlRead_get_ret()
	{
		return $this->var_data[0];
	}

	function xmlRead_parser_file($file)
	{
		unset($this->var_parser);
		if('UTF-8' == strtoupper($this->var_lang))
		{
			$this->var_parser = xml_parser_create('UTF-8');
		}
		else
		{
			$this->var_parser = xml_parser_create();
			if('GBK' == strtoupper($this->var_lang))
			{
				$this->var_lang = $this->var_lang;
			}
		}

		xml_set_object($this->var_parser,&$this);
		xml_parser_set_option($this->var_parser, XML_OPTION_CASE_FOLDING, 0);
		xml_set_element_handler($this->var_parser, "startElement", "endElement");
		xml_set_character_data_handler($this->var_parser, "characterData");
		if (!($fp = fopen($file, "r")))
		{
			die("could not open XML input");
		}

		$data = fread($fp, 4096);
		if('GBK' == $this->var_lang)
		{
			//$data = str_replace(array('utf-8','gb2312','UTF-8','GB2312'),'GBK',$data);
			$data = preg_replace("/encoding=(.+)?>/",'encoding="GBK" ?>',$data);
		}

		elseif('UTF-8' == $this->var_lang)
		{

		}
		do
		{
			if(!xml_parse($this->var_parser, $data, feof($fp)))
			{
				die(sprintf("XML error: %s at line %d",
				xml_error_string(xml_get_error_code($this->var_parser)),
				xml_get_current_line_number($this->var_parser)
				)
				);
			}
		}while($data = fread($fp, 4096));
		xml_parser_free($this->var_parser);
		fclose($fp);
		unset($fp);
	}

	function startElement($parser, $name, $attrs)
	{
		if(function_exists('iconv'))
		{
			$name = iconv('UTF-8', $this->var_lang, $name);
		}

		//节点开始, 节点名入栈
		array_push($this->var_stack,$name);
		array_push($this->var_stack_attrs,$attrs);
		//设置节点深度
		$this->var_depth = count($this->var_stack) - 1;


		if($this->var_depth > 0)
		{

			//判断现在是否只有一个同级同名兄弟结点
			// 当前深度标识的数据是否为一数组 && 是否存在同级同名索引为 $this->var_index[$this->var_depth][$name]] 的记录存在
			// 或同级同名兄弟结点数据为字符串
			if(is_array($this->var_data[$this->var_depth][$name]) && !isset($this->var_data[$this->var_depth][$name][$this->var_index[$this->var_depth][$name]]) || is_string($this->var_data[$this->var_depth][$name]))
			{
				//判断是否有索引设置
				if($this->var_node[$this->var_depth]['node_name'] == $name)
				{
					//如果索引值不存在...
					if(!$this->var_index[$this->var_depth][$name])
					{
						if(intval($this->var_node[$this->var_depth]['target_type']) == 1)
						{
							$index = $this->var_data[$this->var_depth][$name][$this->var_node[$this->var_depth]['target_name']];
							if(is_array($index))
							{
								$this->var_index[$this->var_depth][$name] = 0;
							}
						}
						else
						{
							$this->var_index[$this->var_depth][$name] = $attrs[$this->var_node[$this->var_depth]['target_name']];
						}
					}
				}
				else
				{
					$this->var_index[$this->var_depth][$name] = 0;
				}
				$this->var_data[$this->var_depth][$name] = array($this->var_index[$this->var_depth][$name]=>$this->var_data[$this->var_depth][$name]);
			}

		}
		//检查节点类型,
	}

	function endElement($parser, $name)
	{
		if(function_exists('iconv'))
		{
			$name = iconv('UTF-8', $this->var_lang, $name);
		}
		//判断下级结点数据是否存在
		if(is_array($this->var_data[$this->var_depth+1]) && count($this->var_data[$this->var_depth+1]))
		{
			//判断同级结点是否存在 如在标签结束时同级结点存在的话那在这级同名结点为多数 同级同名首结点在startElement里判断并重命名索引
			//同级同名索引存在否 && 同级同名索引数据存在否
			if(isset($this->var_index[$this->var_depth][$name]) && isset($this->var_data[$this->var_depth][$name][$this->var_index[$this->var_depth][$name]]))
			{
				//判断是否要设置结点索引
				if($this->var_node[$this->var_depth]['node_name'] == $name)
				{
					if($this->var_node[$this->var_depth]['target_type'] == 0)
					{
						$attrs = end($this->var_stack_attrs);
						if(count($attrs))
						{
							$index = $attrs[$this->var_node[$this->var_depth]['target_name']];
						}
					}
					else
					{
						$index = $this->var_data[$this->var_depth+1][$this->var_node[$this->var_depth]['target_name']];
					}
					$this->var_data[$this->var_depth][$name][$index] = $this->var_data[$this->var_depth+1];
				}
				else
				{
					$this->var_data[$this->var_depth][$name][] = $this->var_data[$this->var_depth+1];
				}
			}
			else
			{
				$this->var_data[$this->var_depth][$name] = $this->var_data[$this->var_depth+1];
				//在还没有同级结点的时候,判断是否要设置索引
				if($this->var_node[$this->var_depth]['node_name'] == $name)
				{
					if(intval($this->var_node[$this->var_depth]['target_type']) == 1)
					{
						$index = $this->var_data[$this->var_depth][$name][$this->var_node[$this->var_depth]['target_name']];
						if(is_array($index))
						{
							$index = 0;
						}
					}
					else
					{
						$attrs = end($this->var_stack_attrs);
						$index = $attrs[$this->var_node[$this->var_depth]['target_name']];
					}

					//设置索引值
					$this->var_index[$this->var_depth][$name] = $index;
				}
				else
				{
					//索引默认为 0
					$this->var_index[$this->var_depth][$name] = 0;
				}
			}
		}
		unset($this->var_data[$this->var_depth+1]);
		unset($this->var_index[$this->var_depth+1]);
		//print_r($this->var_data[$this->var_depth][$name]);
		//echo " : $name<br>";
		//节点结束, 节点名出栈
		array_pop($this->var_stack);
		array_pop($this->var_stack_attrs);
		$this->var_depth = count($this->var_stack) - 1;
	}

	function characterData($parser,$data)
	{
		if(trim($data) !== '')
		{
			$name = end($this->var_stack);
			if(function_exists('iconv'))
			{
				$data = iconv('UTF-8', $this->var_lang, $data);
			}
			//echo $data."<br>";
			//判断是否已经有同级并同名的记录存在
			if(is_array($this->var_data[$this->var_depth][$name]))
			{
				//判断是否要设置结点索引
				if($this->var_node[$this->var_depth]['node_name'] == $name && $this->var_node[$this->var_depth]['target_type'] == 0)
				{
					$attrs = end($this->var_stack_attrs);
					if(count($attrs))
					{
						$index = $attrs[$this->var_node[$this->var_depth]['target_name']];
					}
					$this->var_data[$this->var_depth][$name][$index] = $data;
				}
				else
				{
					$this->var_data[$this->var_depth][$name][] = $data;
				}
			}
			else
			{
				$this->var_data[$this->var_depth][$name] = $data;
				//在还没有同级结点的时候,判断是否要设置索引
				if($this->var_node[$this->var_depth]['node_name'] == $name && $this->var_node[$this->var_depth]['target_type'] == 0)
				{
					$attrs = end($this->var_stack_attrs);
					$index = $attrs[$this->var_node[$this->var_depth]['target_name']];

					//设置索引值
					$this->var_index[$this->var_depth][$name] = $index;
				}
				else
				{
					//索引默认为 0
					$this->var_index[$this->var_depth][$name] = 0;
				}
			}
		}
	}
}
 ?>